package com.algo.tools.dataset_converter;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
* This class is for converting sequence databases to the SPMF format.
* 
* Copyright (c) 2008-2012 Philippe Fournier-Viger
* 
* This file is part of the SPMF DATA MINING SOFTWARE
* (http://www.philippe-fournier-viger.com/spmf).
*
* SPMF is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SPMF is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SPMF.  If not, see <http://www.gnu.org/licenses/>.
*/
public class SequenceDatabaseConverter {
	
	String input;
	String output;
	int lineCount =0;
	BufferedWriter writer;

	public void convert(String input, String output, Formats inputFileformat, int lineCount) throws IOException {
		
		this.input = input;
		this.output = output;
		this.lineCount = lineCount;
		
		writer = new BufferedWriter(new FileWriter(output)); 
		
		if(inputFileformat.equals(Formats.IBMGenerator)){
			convertIBMGenerator();
		}
		else if(inputFileformat.equals(Formats.Kosarak)){
			convertKosarak();
		}else if(inputFileformat.equals(Formats.CSV)){
			convertCSV();
		}else if(inputFileformat.equals(Formats.BMS)){
			convertBMS();
		}else if(inputFileformat.equals(Formats.Snake)){
			convertSnake();
		}
		
		writer.flush();
		writer.close();
	}

	private void convertSnake() {
		String thisLine;
		BufferedReader myInput = null;
		try {
			FileInputStream fin = new FileInputStream(new File(input));
			myInput = new BufferedReader(new InputStreamReader(fin));
			int count =0;
			while ((thisLine = myInput.readLine()) != null) {
				if(thisLine.length() >= 11){     // replace by 11 to get 192 sequences 
					for(int i=0; i< thisLine.length(); i++){
						int character = thisLine.toCharArray()[i] - 65;
						writer.write(character + " -1 ");   // WRITE
					}
					writer.write("-2");
				}
				count++;
				if(count == lineCount){
					break;
				}
				writer.newLine();
			}
			myInput.close();
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}

	private void convertBMS() {
		String thisLine;
		BufferedReader myInput = null;
		try {
			FileInputStream fin = new FileInputStream(new File(input));
			myInput = new BufferedReader(new InputStreamReader(fin));
			int lastId = 0;
			int count = 0;
			while ((thisLine = myInput.readLine()) != null) {

				String[] split = thisLine.split(" ");
				int id = Integer.parseInt(split[0]);
				int val = Integer.parseInt(split[1]);
				
				if(lastId != id){
					if(lastId!=0 ){ 
						count++;
						writer.write("-2");
						writer.newLine();
					}
					lastId = id;
				}
				if(count == lineCount){
					break;
				}
				writer.write(val + " -1 ");   // WRITE
			}
			myInput.close();
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}

	private void convertCSV() throws IOException {
		String thisLine;
		BufferedReader myInput = null;
		try {
			FileInputStream fin = new FileInputStream(new File(input));
			myInput = new BufferedReader(new InputStreamReader(fin));
			int count = 0;
			while ((thisLine = myInput.readLine()) != null) {
				// ajoute une squence
				String[] split = thisLine.split(",");
				for (String value : split) {
					Integer item = Integer.parseInt(value);
					writer.write(item + " -1 ");   // WRITE
				}
				writer.write("-2");  
				count++;
				if(count == lineCount){
					break;
				}
				writer.newLine();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (myInput != null) {
				myInput.close();
			}
		}
	}


	private void convertKosarak() throws IOException {
		String thisLine;
		BufferedReader myInput = null;
		try {
			FileInputStream fin = new FileInputStream(new File(input));
			myInput = new BufferedReader(new InputStreamReader(fin));
			int count = 0;
			while ((thisLine = myInput.readLine()) != null) {
				// ajoute une squence
				String[] split = thisLine.split(" ");
				for (String value : split) {
					Integer item = Integer.parseInt(value);
					writer.write(item + " -1 ");   // WRITE
				}
				writer.write("-2");  // NECESSARY?
				count++;
				if(count == lineCount){
					break;
				}
				writer.newLine();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (myInput != null) {
				myInput.close();
			}
		}
	}

	private void convertIBMGenerator() {
		DataInputStream myInput = null;
		try {
			FileInputStream fin = new FileInputStream(new File(input));
			myInput = new DataInputStream(fin);
			boolean lastMinus1 = false;
			int count = 0;
			while (myInput.available() != 0) {
				int value = INT_little_endian_TO_big_endian(myInput.readInt());
				if (value == -1) { // indicate the end of an itemset
					writer.write("-1 "); // WRITE
					lastMinus1 = true;
				} else if (value == -2) { // indicate the end of a sequence
					// check if the last "-1" was not included
					if (lastMinus1 == false) {
						writer.write("-1 "); // WRITE
					}
					writer.write("-2 ");
					count++;
					if(count == lineCount){
						break;
					}
					writer.newLine();
				} else {
					// extract the value for an item
					writer.write(value + " ");   // WRITE
					lastMinus1 = false;
				}
			}
			myInput.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	// 4-byte number this function was taken from the internet (by Anghel
	// Leonard)
	int INT_little_endian_TO_big_endian(int i) {
		return ((i & 0xff) << 24) + ((i & 0xff00) << 8) + ((i & 0xff0000) >> 8)
				+ ((i >> 24) & 0xff);
	}
}
